/*
 *  Utility functions 
 *                              JunKim 
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>

typedef unsigned char byte;

#define NUMDIGIT                (8)
#define HEADERLEN               (NUMDIGIT + 1)
#define MAXBUFLEN               (MAXDATALEN + NUMDIGIT + 1)

byte  gcmd[2048];
byte  gres[2048];
char* ghost_name;
int   gport;

static unsigned
_str_to_unsigned(byte* p)
{
    char buf[NUMDIGIT + 1];

    strncpy(buf, p, NUMDIGIT);

    return atoi(buf);
}

static void
_unsigned_to_str(unsigned u, byte* p)
{
    char format[8];

    sprintf(format, "%%0%dd", NUMDIGIT);
    sprintf(p, format, u);
}

static int  
_client_connect(char* host_name, int port)
{
    struct sockaddr_in pin;
    struct hostent*    server_host_name;
    int                sock = -1;
    int                r    = -1;

    do
    {
        if ((server_host_name = gethostbyname(host_name)) == 0) break;

        bzero(&pin, sizeof(pin));
        pin.sin_family      = AF_INET;
        pin.sin_addr.s_addr = htonl(INADDR_ANY);
        pin.sin_port        = htons(port);
        pin.sin_addr.s_addr = 
            ((struct in_addr *)(server_host_name->h_addr))->s_addr;

        sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1) break;

        r = connect(sock, (void *)&pin, sizeof(pin));
        if (r == -1) 
        {
            perror(" Client connection error ");
            sock = -1;
            break;
        }
    } while (0);

    return sock;
}

void 
store_init(char* host_name, int port)
{
    ghost_name = host_name;
    gport      = port;
}

int  
store_put(int sock, unsigned length, byte* data, unsigned* key)
{
    int      r; 

    gcmd[0] = 'P';

    _unsigned_to_str(length, gcmd + 1);
    memcpy(gcmd + HEADERLEN, data, length);

    do
    {
        r = send(sock, gcmd, length + HEADERLEN, 0);
        if (r == -1) break;

        r = recv(sock, gres, 2048, 0); 
        if (r == -1) break;

        if (gres[0] == 'A')
        {
            *key = _str_to_unsigned(gres + 1);
            r    = 0;
        }
        else r = -1;
    } while (0);

    return r;
}

int  
store_get(int sock, unsigned key, unsigned bsize, byte* buffer, 
          unsigned* length)
{
    int r;

    gcmd[0] = 'G';
    _unsigned_to_str(key, gcmd + 1);

    do
    {
        r = send(sock, gcmd, HEADERLEN, 0);
        if (r == -1) break;

        r = recv(sock, gres, 2048, 0); 
        if (r == -1) break;

        if (gres[0] == 'D')
        {
            *length = _str_to_unsigned(gres + 1);
            if (*length <= bsize)
            {
                memcpy(buffer, gres + HEADERLEN, *length);
            }
            r = 0;
        }
    } while (0);

    return r;
}

int  
store_remove(int sock, unsigned key)
{
    int r;

    gcmd[0] = 'R';
    _unsigned_to_str(key, gcmd + 1);

    do
    {
        r = send(sock, gcmd, HEADERLEN, 0);
        if (r == -1) break;

        r = recv(sock, gres, 2048, 0);
        if (r == -1) break;

        if (gres[0] == 'O')
        {
            r = 0;
        }
    } while (0);

    return r;
}

byte buffer[1000];

int
main(int argc, char* argv[])
{
    unsigned key1;
    unsigned key2;
    int      r;
    char*    msg1 = "message1";
    char*    msg2 = "message2";
    unsigned len;
    int      socket;

    if (argc == 2) 
    {
        socket = _client_connect(argv[1], 2201);
    }
    else
    {
        socket = _client_connect("localhost", 2201);
    }

    if (socket < 0) return -1;

    r = store_put(socket, strlen(msg1), msg1, &key1);
    printf("store_put() = %d, key = %08d\n", r, key1);

    r = store_put(socket, strlen(msg2), msg2, &key2);
    printf("store_put() = %d, key = %08d\n", r, key2);

    r = store_get(socket, key1, 1000, buffer, &len);
    if (r == 0) buffer[len] = '\0';
    printf("store_get(key = %08d) = %d, %s\n", key1, r, buffer);

    r = store_get(socket, key2, 1000, buffer, &len);
    if (r == 0) buffer[len] = '\0';
    printf("store_get(key = %08d) = %d, %s\n", key2, r, buffer);

    r = store_remove(socket, key1);
    printf("store_remove() = %d\n", r);

    //r = store_remove(key2);
    //printf("store_remove() = %d\n", r);

    r = store_get(socket, key1, 1000, buffer, &len);
    if (r == 0) buffer[len] = '\0';
    printf("store_get(key = %08d) = %d, %s\n", key1, r, buffer);

    r = store_get(socket, key2, 1000, buffer, &len);
    if (r == 0) buffer[len] = '\0';
    printf("store_get(key = %08d) = %d, %s\n", key2, r, buffer);

    close(socket);    
}
